package com.seqb.manage.reptile.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.seqb.common.FileType;
import com.seqb.common.ResultVo;
import com.seqb.common.config.SeqbConfig;
import com.seqb.common.mybatis.WrapperHandler;
import com.seqb.exception.BdException;
import com.seqb.manage.choice.dao.ChoiceQuestionDao;
import com.seqb.manage.choice.domain.ChoiceQuestionDO;
import com.seqb.manage.file.dao.FileDao;
import com.seqb.manage.file.domain.FileDO;
import com.seqb.manage.file.service.FileService;
import com.seqb.manage.paper.dao.PaperDao;
import com.seqb.manage.paper.dao.PaperQuestionDao;
import com.seqb.manage.paper.domain.PaperDO;
import com.seqb.manage.paper.domain.PaperQuestionDO;
import com.seqb.manage.reptile.dao.ReptileDataDao;
import com.seqb.manage.reptile.domain.ReptileDataDO;
import com.seqb.manage.reptile.service.ReptileDataService;
import com.seqb.manage.subject.dao.SubjectDao;
import com.seqb.manage.subject.domain.SubjectDO;
import com.seqb.manage.synthesis.dao.SynthesisQuestionDao;
import com.seqb.manage.synthesis.domain.SynthesisQuestionDO;
import com.seqb.utils.FileUtils;
import com.seqb.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * @author lilinshen
 * @title 爬取数据表
 * @description 请填写相关描述
 * @date 2020-01-16
 */
@Service
public class ReptileDataServiceImpl implements ReptileDataService {

    @Autowired
    private FileDao fileDao;
    @Autowired
    private PaperDao paperDao;
    @Value("${server.servlet.context-path}")
    private String contextPath;
    @Autowired
    private SeqbConfig seqbConfig;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private FileService fileService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ReptileDataDao reptileDataDao;
    @Autowired
    private PaperQuestionDao paperQuestionDao;
    @Autowired
    private ChoiceQuestionDao choiceQuestionDao;
    @Autowired
    private SynthesisQuestionDao synthesisQuestionDao;

    @Override
    public ReptileDataDO get(Long id) {
        return reptileDataDao.selectById(id);
    }

    @Override
    public Page<ReptileDataDO> list(Map<String, Object> map) {
        if (null != map && null != map.get("pageNumber") && null != map.get("pageSize")) {
            PageHelper.startPage(Integer.valueOf(map.get("pageNumber").toString()), Integer.valueOf(map.get("pageSize").toString()));
        } else {
            PageHelper.startPage(1, Integer.MAX_VALUE);
        }
        QueryWrapper<ReptileDataDO> queryWrapper = WrapperHandler.genQueryWrapper(map, ReptileDataDO.class);
        queryWrapper.select(ReptileDataDO.class, i -> !i.getColumn().equals("data_content"));
        return (Page<ReptileDataDO>) reptileDataDao.selectList(queryWrapper);
    }

    @Override
    public int count(Map<String, Object> map) {
        QueryWrapper queryWrapper = WrapperHandler.genQueryWrapper(map, ReptileDataDO.class);
        return reptileDataDao.selectCount(queryWrapper);
    }

    @Override
    @Transactional
    public int save(ReptileDataDO reptileData) {
        return reptileDataDao.insert(reptileData);
    }

    @Override
    @Transactional
    public int update(ReptileDataDO reptileData) {
        return reptileDataDao.updateById(reptileData);
    }

    @Override
    @Transactional
    public int remove(Long id) {
        return reptileDataDao.deleteById(id);
    }

    @Override
    @Transactional
    public int batchRemove(Long[] ids) {
        return reptileDataDao.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo reptile(Long id) {
        try {
            String dataContent = "";
            QueryWrapper queryWrapper = new QueryWrapper();
            if (null != id) {
                queryWrapper.eq("id", id);
            }
            List<ReptileDataDO> list = reptileDataDao.selectList(queryWrapper);
            if (null != list && list.size() > 0) {
                for (ReptileDataDO reptileData : list) {
                    String dataUrl = reptileData.getDataUrl();
                    String dataParams = reptileData.getDataParams();
                    String dataMethod = reptileData.getDataMethod();
                    String dataType = reptileData.getDataType();
                    ResultVo result = reptileData(dataUrl, dataParams, dataMethod);
                    if (String.valueOf(result.get("code")).equals("0")) {
                        ReptileDataDO updateDO = new ReptileDataDO();
                        dataContent = String.valueOf(result.get("data"));
                        updateDO.setId(reptileData.getId());
                        updateDO.setDataContent(String.valueOf(result.get("data")));
                        reptileDataDao.updateById(updateDO);
                    }
                }
            }
            if (null != id) {
                return ResultVo.ok().put("data", dataContent);
            } else {
                return ResultVo.ok();
            }
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return ResultVo.error();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo updatePaper(Long id, Long paperId) {
        try {
            if (null == id) {
                return ResultVo.error("缺少参数！");
            }
            ReptileDataDO reptileData = reptileDataDao.selectById(id);
            if (null == reptileData) {
                return ResultVo.error("该爬取数据不存在！");
            }
            String dataContent = reptileData.getDataContent();
            if (StringUtils.isEmpty(dataContent)) {
                return ResultVo.error("该爬取数据的爬取结果为空，请爬取结果后再操作！");
            }
            //解析爬取结果
            List<Map<String, Object>> resultList = parseDataContent(dataContent);
            if (null == resultList || resultList.size() == 0) {
                return ResultVo.error("爬取结果解析失败！");
            }
            if (null != paperId) {
                //更新已存在的试题
                PaperDO paper = paperDao.selectById(paperId);
                if (null == paper) {
                    return ResultVo.error("该试题Id不存在！");
                }
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("paper_id", paperId);
                List<PaperQuestionDO> questionList = paperQuestionDao.selectList(queryWrapper);
                for (int i = 0; i < resultList.size(); i++) {
                    String answer = String.valueOf(((Map) resultList.get(i)).get("answer"));
                    String answerAnalysis = String.valueOf(((Map) resultList.get(i)).get("answerAnalysis"));
                    String sortNumber = String.valueOf(((Map) resultList.get(i)).get("sortNumber"));
                    for (int j = 0; j < questionList.size(); j++) {
                        PaperQuestionDO paperQuestion = questionList.get(j);
                        if (String.valueOf(paperQuestion.getSortNumber()).equals(sortNumber)) {
                            Long questionId = paperQuestion.getQuestionId();
                            if (resultList.size() > 70) {
                                ChoiceQuestionDO choiceQuestion = choiceQuestionDao.selectById(questionId);
                                if (choiceQuestion == null) {
                                    break;
                                }
                                ChoiceQuestionDO updateDO = new ChoiceQuestionDO();
                                updateDO.setId(choiceQuestion.getId());
                                updateDO.setAnswer(answer);
                                updateDO.setAnswerAnalysis(answerAnalysis);
                                choiceQuestionDao.updateById(updateDO);
                                break;
                            } else {
                                SynthesisQuestionDO choiceQuestion = synthesisQuestionDao.selectById(questionId);
                                if (choiceQuestion == null) {
                                    break;
                                }
                                SynthesisQuestionDO updateDO = new SynthesisQuestionDO();
                                updateDO.setId(choiceQuestion.getId());
                                updateDO.setAnswer(answer);
                                updateDO.setAnswerAnalysis(answerAnalysis);
                                synthesisQuestionDao.updateById(updateDO);
                                break;
                            }
                        }
                    }
                }
            } else {
                //新增试题，试卷
                if (resultList.size() > 70) {
                    Long subjectId = null;
                    for (int i = 0; i < resultList.size(); i++) {
                        Map<String, Object> question = resultList.get(i);
                        String fileIds = question.get("fileIds") + "";
                        String subjectName = question.get("subjectName") + "";
                        if (i == 0) {
                            QueryWrapper queryWrapper = new QueryWrapper();
                            queryWrapper.eq("name", subjectName);
                            SubjectDO subject = subjectDao.selectOne(queryWrapper);
                            if (null != subject) {
                                subjectId = subject.getId();
                            }
                        }
                        ChoiceQuestionDO choiceQuestion = new ChoiceQuestionDO();
                        choiceQuestion.setSubjectId(subjectId);
                        choiceQuestion.setSubjectName(subjectName);
                        choiceQuestion.setName(question.get("name") + "");
                        Long sortNumber = Long.valueOf(question.get("sortNumber") + "");
                        choiceQuestion.setSortNumber(sortNumber);
                        choiceQuestion.setType(question.get("type") + "");
                        choiceQuestion.setChoiceOption(question.get("choiceOption") + "");
                        choiceQuestion.setOptionType(question.get("optionType") + "");
                        choiceQuestion.setAnswer(question.get("answer") + "");
                        choiceQuestion.setAnswerAnalysis(question.get("answerAnalysis") + "");
                        int insert = choiceQuestionDao.insert(choiceQuestion);
                        if (insert <= 0) {
                            throw new BdException("操作失败！");
                        }
                        if (!StringUtils.isEmpty(fileIds)) {
                            //更新附件表数据
                            Long choiceQuestionId = choiceQuestion.getId();
                            String ids = choiceQuestion.getIds();
                            ResultVo resultVo = fileService.updateIds(fileIds, choiceQuestionId, "ChoiceQuestion", "Attachment");
                            if (null != resultVo.get("fileUrl")) {
                                ChoiceQuestionDO choiceQuestionDO = new ChoiceQuestionDO();
                                choiceQuestionDO.setId(choiceQuestion.getId());
                                choiceQuestionDO.setFileUrl(String.valueOf(resultVo.get("fileUrl")));
                                int update = choiceQuestionDao.updateById(choiceQuestionDO);
                                if (update <= 0) {
                                    throw new BdException("操作失败！");
                                }
                            }
                        }
                    }
                }
            }
            //更新处理状态
            ReptileDataDO updateDO = new ReptileDataDO();
            updateDO.setId(reptileData.getId());
            updateDO.setDataProcessed("1");
            reptileDataDao.updateById(updateDO);
            return ResultVo.ok();
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return ResultVo.error();
    }

    public ResultVo reptileData(String dataUrl, String dataParams, String dataMethod) {
        try {
            if (StringUtils.isEmpty(dataUrl)) {
                return ResultVo.error();
            }
            HttpHeaders headers = new HttpHeaders();
            MultiValueMap<String, Object> requestMap = new LinkedMultiValueMap<>();
            dataUrl = setRequestParams(headers, requestMap, dataUrl, dataParams, dataMethod);
            HttpMethod httpMethod = getRequestMathod(dataMethod);
            HttpEntity httpEntity = new HttpEntity(requestMap, headers);
            ResponseEntity<String> responseEntity = restTemplate.exchange(dataUrl, httpMethod, httpEntity, String.class);
            HttpStatus status = responseEntity.getStatusCode();
            if (status.equals(HttpStatus.OK)) {
                String resultData = responseEntity.getBody();
                return ResultVo.ok().put("data", resultData);
            }
            return ResultVo.error();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResultVo.error();
    }

    /**
     * 封装请求所需的参数
     */
    private String setRequestParams(HttpHeaders headers, MultiValueMap<String, Object> map, String dataUrl, String dataParams, String dataMethod) {
        StringBuffer requestUtl = new StringBuffer(dataUrl);
        if (!StringUtils.isEmpty(dataParams)) {
            JSONArray paramsArray = JSON.parseArray(dataParams);
            for (int i = 0; i < paramsArray.size(); i++) {
                JSONObject paramsObject = paramsArray.getJSONObject(i);
                String type = paramsObject.getString("type");
                JSONArray valueArray = paramsObject.getJSONArray("value");
                if ("header".equals(type) && valueArray.size() > 0) {
                    for (int j = 0; j < valueArray.size(); j++) {
                        JSONObject valueObject = valueArray.getJSONObject(j);
                        String key = valueObject.getString("key");
                        String value = valueObject.getString("value");
                        headers.add(key, value);
                    }
                }
                if ("cookie".equals(type) && valueArray.size() > 0) {
                    List<String> cookieList = new ArrayList<>();
                    for (int j = 0; j < valueArray.size(); j++) {
                        JSONObject valueObject = valueArray.getJSONObject(j);
                        String key = valueObject.getString("key");
                        String value = valueObject.getString("value");
                        cookieList.add(key + "=" + value);
                    }
                    headers.put("Cookie", cookieList);
                }
                if ("params".equals(type) && valueArray.size() > 0) {
                    if ("get".equals(dataMethod)) {
                        requestUtl.append("?");
                        for (int j = 0; j < valueArray.size(); j++) {
                            JSONObject valueObject = valueArray.getJSONObject(j);
                            String key = valueObject.getString("key");
                            String value = valueObject.getString("value");
                            if (!StringUtils.isEmpty(value)) {
                                requestUtl.append(key).append("=").append(value).append("&");
                            }
                        }
                        dataUrl = requestUtl.substring(0, requestUtl.length() - 1);
                    } else if ("post".equals(dataMethod)) {
                        for (int j = 0; j < valueArray.size(); j++) {
                            JSONObject valueObject = valueArray.getJSONObject(j);
                            String key = valueObject.getString("key");
                            String value = valueObject.getString("value");
                            map.add(key, value);
                        }
                    }
                }
            }
        }
        return dataUrl;
    }

    /**
     * 获取请求的方法类型
     */
    private HttpMethod getRequestMathod(String dataMethod) {
        if (dataMethod.equals("get")) {
            return HttpMethod.GET;
        } else if (dataMethod.equals("head")) {
            return HttpMethod.HEAD;
        } else if (dataMethod.equals("post")) {
            return HttpMethod.POST;
        } else if (dataMethod.equals("put")) {
            return HttpMethod.PUT;
        } else if (dataMethod.equals("patch")) {
            return HttpMethod.PATCH;
        } else if (dataMethod.equals("delete")) {
            return HttpMethod.DELETE;
        } else if (dataMethod.equals("options")) {
            return HttpMethod.OPTIONS;
        } else if (dataMethod.equals("trace")) {
            return HttpMethod.TRACE;
        }
        return HttpMethod.GET;
    }

    /**
     * 解析爬取结果，封装到一个
     */
    private List<Map<String, Object>> parseDataContent(String dataContent) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        try {
            Map<String, Object> resultMap = null;
            if (StringUtils.isEmpty(dataContent)) {
                return resultList;
            }
            JSONObject root = JSON.parseObject(dataContent);
            if (null == root.get("data")) {
                return resultList;
            }
            JSONObject data = root.getJSONObject("data");
            if (null == data.get("data")) {
                return resultList;
            }
            JSONObject dataData = data.getJSONObject("data");
            if (null == dataData.get("question")) {
                return resultList;
            }
            JSONArray questionArr = dataData.getJSONArray("question");
            for (int i = 0; i < questionArr.size(); i++) {
                resultMap = new HashMap<>();
                JSONObject question = (JSONObject) questionArr.get(i);
                String title = question.getString("title").trim();
                String subjectName = question.getString("knowledge").trim();
                String name = question.getString("question_title").trim();
                String fileIds = handleImgIds(name);
                Document nameDoc = Jsoup.parse(name);
                name = nameDoc.text().trim();
                if (name.substring(name.length() - 1).equals(".")) {
                    name = name.substring(0, name.length() - 1) + "。";
                }
                if (!name.substring(name.length() - 1).equals("。")) {
                    name = name + "。";
                }

                Long sortNumber = question.getLong("index");
                Map<String, Object> optionMap = new HashMap<>();
                JSONArray optionArr = question.getJSONArray("option");
                for (int j = 0; j < optionArr.size(); j++) {
                    String option = optionArr.getString(j).trim();
                    if (j == 0) {
                        optionMap.put("A", option);
                    } else if (j == 1) {
                        optionMap.put("B", option);
                    } else if (j == 2) {
                        optionMap.put("C", option);
                    } else if (j == 3) {
                        optionMap.put("D", option);
                    }
                }
                String option = JsonUtils.beanToJson(optionMap);
                String answer = question.getJSONArray("answer").getString(0).trim();
                answer = handleImgStr(answer);
                String answerAnalysis = question.getString("analyze").trim();
                answerAnalysis = handleImgStr(answerAnalysis);

                resultMap.put("paper", title);
                resultMap.put("subjectName", subjectName);
                resultMap.put("name", name);
                resultMap.put("sortNumber", sortNumber);
                resultMap.put("type", "1");
                resultMap.put("choiceOption", option);
                resultMap.put("optionType", "1");
                resultMap.put("answer", answer);
                resultMap.put("answerAnalysis", answerAnalysis);
                resultMap.put("fileIds", fileIds);
                resultList.add(resultMap);
            }
            return resultList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }

    /**
     * 处理内容里面的img标签
     */
    private String handleImgIds(String content) {
        StringBuffer fileIds = new StringBuffer();
        Document contentDoc = Jsoup.parse(content);
        Elements imgs = contentDoc.select("img");
        for (int j = 0; j < imgs.size(); j++) {
            Element img = imgs.get(j);
            String src = img.attr("src");
            String fileName = FileUtils.renameSuffix(FileUtils.renameToUuid(src));
            String fileUrl = "/files/" + FileUtils.generatePath() + fileName;
            String filePath = seqbConfig.getUploadPath() + FileUtils.generatePath() + fileName;
            boolean flag = FileUtils.downloadFile(src, filePath);
            if (flag) {
                String oldFileName = src.substring(src.lastIndexOf("/") + 1);
                FileDO file = new FileDO(FileType.fileType(oldFileName), fileUrl, oldFileName, null);
                int insert = fileDao.insert(file);
                if (insert > 0) {
                    fileIds.append(file.getId() + ",");
                }
            }
        }
        return fileIds.toString();
    }

    /**
     * 处理内容里面的img标签
     */
    private String handleImgStr(String content) {
        Document contentDoc = Jsoup.parse(content);
        Elements imgs = contentDoc.select("img");
        FileDO file = null;
        for (int j = 0; j < imgs.size(); j++) {
            Element img = imgs.get(j);
            String src = img.attr("src");
            String fileName = FileUtils.renameSuffix(FileUtils.renameToUuid(src));
            String fileUrl = "/files/" + FileUtils.generatePath() + fileName;
            String filePath = seqbConfig.getUploadPath() + FileUtils.generatePath() + fileName;
            boolean flag = FileUtils.downloadFile(src, filePath);
            if (flag) {
                String oldFileName = src.substring(src.lastIndexOf("/") + 1);
                file = new FileDO(FileType.fileType(oldFileName), fileUrl, oldFileName, null);
                fileDao.insert(file);
                img.attr("src", contextPath + fileUrl);
            }
        }
        content = contentDoc.select("body").html().toString();
        return content;
    }

}